﻿/*===================================================
* CLR版本  : 4.0.30319.42000 
* 类名称   : Entity
* 文 件 名 : Entity 
* 类描述   :
* 创建人   : oream
* 创建时间 : 2018/2/11 0:12:03
* 修改人   : 
* 修改时间 :
* 版本： @version 1.0
=====================================================*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;

namespace Hotfix
{
  public class Entity : Component
  {
    private readonly HashSet<Component> components;

    private readonly Dictionary<Type, Component> dicComponentDict;


    protected Entity()
    {
      this.id = IDHellper.ProduceID();
      this.dicComponentDict = new Dictionary<Type, Component>();
      this.components = new HashSet<Component>();
    }

    protected Entity(long id)
    {
      this.id = id;
      this.dicComponentDict = new Dictionary<Type, Component>();
      this.components = new HashSet<Component>();
    }

    public override void Dispose()
    {
      if (this.id == 0)
      {
        return;
      }
      base.Dispose();

      foreach (Component component in this.GetComponent())
      {
        try
        {
          component.Dispose();
        }
        catch (Exception e)
        {
          Debug.LogError(e.ToString());
          throw;
        }
      }

      this.components.Clear();
      this.dicComponentDict.Clear();
    }

    public Component[] GetComponent()
    {
      return this.dicComponentDict.Values.ToArray();
    }

    #region AddComponent

    public T AddComponent<T>() where T : Component, new()
    {
      T component = ComponentFactory.Create<T>(this);
      if (this.dicComponentDict.ContainsKey(component.GetType()))
      {
        throw new Exception($"AddComponent, component already exist, id: {this.id}, component: {typeof(T).Name}");
      }
      if (component is ISerializeToEntity)
      {
        this.components.Add(component);
      }
      this.dicComponentDict.Add(component.GetType(), component);
      return component;
    }
    public T AddComponent<T, A>(A a) where T : Component, new()
    {
      T component = ComponentFactory.Create<T, A>(this, a);
      if (this.dicComponentDict.ContainsKey(component.GetType()))
      {
        throw new Exception($"AddComponent, component already exist, id: {this.id}, component: {typeof(T).Name}");
      }
      if (component is ISerializeToEntity)
      {
        this.components.Add(component);
      }
      this.dicComponentDict.Add(component.GetType(), component);
      return component;
    }

    public T AddComponent<T, A, B>(A a, B b) where T : Component, new()
    {
      T component = ComponentFactory.Create<T, A, B>(this, a, b);
      if (this.dicComponentDict.ContainsKey(component.GetType()))
      {
        throw new Exception($"AddComponent, component already exist, id: {this.id}, component: {typeof(T).Name}");
      }
      if (component is ISerializeToEntity)
      {
        this.components.Add(component);
      }
      this.dicComponentDict.Add(component.GetType(), component);
      return component;
    }

    public T AddComponent<T, A, B, C>(A a, B b, C c) where T : Component, new()
    {
      T component = ComponentFactory.Create<T, A, B, C>(this, a, b, c);
      if (this.dicComponentDict.ContainsKey(component.GetType()))
      {
        throw new Exception($"AddComponent, component already exist, id: {this.id}, component: {typeof(T).Name}");
      }
      if (component is ISerializeToEntity)
      {
        this.components.Add(component);
      }
      this.dicComponentDict.Add(component.GetType(), component);
      return component;
    }
    #endregion

    #region RemoveComponent

    public void RemoveComponent(Type type)
    {
      if (this.dicComponentDict.TryGetValue(type, out Component component))
      {
        this.dicComponentDict.Remove(type);
        this.components?.Remove(component);
      }
    }


    public void RemoveComponent<T>() where T : Component
    {
      RemoveComponent(typeof(T));
    }

    #endregion

    #region GetComponent

    public Component GetComponent(Type type)
    {
      if (this.dicComponentDict.TryGetValue(type, out Component component))
      {
        return component;
      }
      return null;
    }

    public T GetComponent<T>() where T : Component
    {
      return (T)GetComponent(typeof(T));
    }

    public Component[] GetComponents()
    {
      return this.dicComponentDict.Values.ToArray();
    }

    #endregion
  }
}
